import {
  Mesh,
  Object3D,
  Raycaster,
  SphereGeometry,
  Vector3
} from 'three'
import { App } from '../../../application'
import { Point } from '../../../renderExtension/types/Point'
import Polyline from '../../models/Polyline'
import { CustomMeshBasicMaterial } from '../../../renderExtension/Material/CustomMaterial'
import { TransformControls } from 'three/examples/jsm/controls/TransformControls'
import Helper from '../../../utils/Helper'
import Const from '../../../application/constants/Const'
import MeshUtil from '../../../renderExtension/utils/MeshUtil'
import HtmlMarker from '../../models/HtmlMarker'
import RouteLine from './RouteLine'
import RouteArrow from './RouteArrow'
import Waypoint from './Waypoint'
import Config from '../../../application/constants/Config'

/**
 * 编辑已存在的路线
 */
export default class EditRoute{
  private app: App
  private routeLine: RouteLine
  private routeArrow: RouteArrow;
  private wapPoint: Waypoint;
  private isStartEdit = false

  private flightParam: {
    realLine: Polyline,
    lineScale?: number,
    sphereScale?: number,
    grounds?: Array<Object3D>,
    minDistanceFromGround: number,
    maxDistanceFromGround: number,
    sidewipeDistance: number,
    keybordDistance?: number,
    narrowCountFactor?: number,
    stencilRef?: number,
    narrorColor?: string,
  }
  private verticalParam: { lineWidth: number; lineColor: string }
  private flightRange: {circelCenter: Point, circleRadius: number};

  public constructor(
    flightParam: {
      realLine: Polyline,
      lineScale?: number,
      sphereScale?: number,
      grounds?: Array<Object3D>,
      minDistanceFromGround: number,
      maxDistanceFromGround: number,
      sidewipeDistance: number,
      keybordDistance?: number,
      narrowCountFactor?: number,
      stencilRef?: number,
      narrorColor?: string, 
    },
    verticalParam: { lineWidth: number; lineColor: string }, flightRange?: {circelCenter: Point, circleRadius: number}
  ) {
    this.app = App.getInstance()

    this.flightParam = flightParam
    this.verticalParam = verticalParam || { lineWidth: 5, lineColor: '#FFFFFF' }
    this.flightRange = flightRange;
    
    if (!this.flightParam.lineScale) {
      this.flightParam.lineScale = 5
    }
    if (!this.flightParam.sphereScale) {
      this.flightParam.sphereScale = 2.5
    }

    this.init()
  }

  public init() {
    this.routeLine = new RouteLine(this.flightParam, this.lineClickEvent.bind(this));
    
    this.routeArrow = new RouteArrow({pointArray: this.routeLine.getPointArray(), narrowCountFactor: this.flightParam.narrowCountFactor, narrorColor: this.flightParam.narrorColor,  stencilRef: this.flightParam.stencilRef});
    this.wapPoint = new Waypoint({grounds: this.flightParam.grounds, minDistanceFromGround: this.flightParam.minDistanceFromGround, maxDistanceFromGround: this.flightParam.maxDistanceFromGround, sphereScale: this.flightParam.lineScale,routeArrow: this.routeArrow, routeLine: this.routeLine, keybordDistance: this.flightParam.keybordDistance}, 
    this.verticalParam || { lineWidth: 5, lineColor: '#FFFFFF' }, this.flightRange);
  }

  public startOperator(isEdit:boolean=true) {
    if(isEdit){
      this.isStartEdit = true;

      this.wapPoint.startOperator(true);
    }else{
       this.isStartEdit = false;
       this.wapPoint.startOperator(false);
    }
  }

  public dispose() {
    this.isStartEdit = false

    this.routeLine.dispose();
    this.wapPoint.dispose();
    this.routeArrow.removeLineNarrow();
  }

  /**
   * 获取一个位置在地图数据上对高度做调整后的位置
   * @param targetPosition 
   * @returns 
   */
  public getVerticalTopPoint(targetPosition) {
    let rayDirection = new Vector3(0, 0, -1)
    let rayBeginPosition = targetPosition
    rayBeginPosition.z = 10000000
    let raycaster: Raycaster = new Raycaster(rayBeginPosition, rayDirection)
    raycaster.camera = this.app.three.camera
    try {
      let ground = this.flightParam.grounds
      if (!ground || ground.length == 0) {
        ground = [this.app.three.scene]
      }
      let objArray = raycaster.intersectObjects(ground, true)
      if (objArray.length > 0) {
        let insertedPoint = objArray[0].point
        let newPoint = new Point(
          insertedPoint.x,
          insertedPoint.y,
          insertedPoint.z,
          Const.EPSGType.EPSGWeb
        )
        return newPoint
      }
    } catch (error) {
      console.log(error)
      return null
    }
    return null
  }

  public lineClickEvent(e) {
    // if (!this.isStartEdit) {
    //   return false;
    // }

    let insertedPointMsg = this.routeLine.lineClickEvent(e);
    if(!insertedPointMsg){
      return false;
    }
    this.wapPoint.pointClickEvent(insertedPointMsg);

    let pointIndex = insertedPointMsg.fitIndex+1;
    this.app.fireEvent(Const.FlightRoute.changeWayPoint, 'addPoint', pointIndex);
    return true;
  }

   public unSelectClickEvent(e?) {
    this.wapPoint.unSelectClickEvent(e)
   }

  public selectWaypoint(index){
    this.wapPoint.selectWayPoint(index);
  }

  /**
   * 添加一个点到路线的末尾
   */
  public addPoint(point: Point) {
    point.toEPSGWeb()

    let pointArray = this.routeLine.getPointArray()
    if (pointArray.length > 0) {
      let lastPoint = pointArray[pointArray.length - 1]
      if (Helper.vector3Equals(lastPoint, point)) {
        //新的顶点和路线末尾的顶点相同，不处理
        return
      }
      let previousPoint = pointArray[pointArray.length - 1]
      this.routeArrow.buildNarrow(previousPoint, point, true)
    }

    this.routeLine.addPoint(point);
    this.wapPoint.addWaypoint(point);

    this.app.fireEvent(Const.FlightRoute.changeWayPoint, 'addPoint', pointArray.length-1);
  }

  public getRoutePointArray() {
    let linePointArray = this.routeLine.getPointArray()
    let routePointArray = []
    linePointArray.forEach((element) => {
      let tempPoint = element.clone().toGeography();
      routePointArray.push(tempPoint)
    })
    return routePointArray
  }


  public removePoint(index: number) {
    this.routeLine.removePoint(index)
    this.wapPoint.removeWaypoint(index);
    this.routeArrow.removeLineNarrow();
    this.routeArrow.initLineNarrow(true);

     this.app.fireEvent(Const.FlightRoute.changeWayPoint, 'removePoint', index);
  }

  public updatePoint(index: number, newPoint: Point, isNotify: boolean){
      if(this.flightRange && !this.isInRange(newPoint.clone())){ //航点超出了最大范围
        this.app.fireEvent(Const.FlightRoute.crossRange);
        return;
      }

      this.checkHeight(index, newPoint);
      this.routeLine.updatePoint(index, newPoint.clone());
      
      this.wapPoint.updateWaypoint(index, newPoint.clone())
      this.routeArrow.updateLineNarrow();

      if(isNotify){
        this.app.fireEvent(Const.FlightRoute.changeWayPoint, 'updatePoint', index);
      }
  }

  public checkFlightSafe(): boolean{
    if(!this.routeLine){
      return false;
    }
    return this.routeLine.checkSafe();
  }

  private isInRange(point: Point){
    let circelCenter = this.flightRange.circelCenter.clone().toEPSGWeb();
    point.z = 0;
    point = point.toEPSGWeb();

    let distance = point.distanceTo(circelCenter);
    if(distance > this.flightRange.circleRadius){
      return false;
    }
    return true;
  }

  private checkHeight(index, newPoint){
      let dangerSign = 0; //危险标识，0标识高度太低，1标识高度太高
      if(newPoint.z < this.flightParam.minDistanceFromGround){
        newPoint.z = this.flightParam.minDistanceFromGround;
        dangerSign = 0;
        this.app.fireEvent(Const.FlightRoute.dangerWaypoint, dangerSign, index);
        return true;
      }else if(newPoint.z > this.flightParam.maxDistanceFromGround){
        newPoint.z = this.flightParam.maxDistanceFromGround;
        dangerSign = 1;
        this.app.fireEvent(Const.FlightRoute.dangerWaypoint, dangerSign, index);
         return true;
      }
       return false;
  }
}
